package oop.ex1.filters;

import java.io.*;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.TreeSet;

import oop.ex1.filters.YesNoException;
import oop.ex1.filters.FilterNameException;


/**This class handles the filtering process in this program.
 * @author miron_6 & dawn16889
 *
 */
public class FiltersWork {
	
	private static final String FUNCTION_SPLITER = "%";


	/**this method uses Filter emuns as written in the exercise description in order to decide which 
	 * filter needs to be made.  
	 * @param filterName - the String containing the filter's name
	 * @param filteringParam - the filter's parameter (e.g. date, yes/no, size etc).
	 * @return the required filter according to the given string.
	 * @throws YesNoException if the given String in neither YES nor NO.
	 * @throws FilterNameException if a given filter name is illegal. 
	 * @throws IllegalDateException if date is illegal.
	 */
	public static FileFilter getFilter(String filterName ,String filteringParam)
									throws  YesNoException, FilterNameException, IllegalDateException{
		try {
			eFilters fil = eFilters.valueOf(filterName);
			switch (fil){ //finding a match to one of the eFilters enums. 
			case before:
				return new Filters.Before(filteringParam);
			case after:
				return new Filters.After(filteringParam);
			case greater_than:
				return new Filters.GreaterThan(filteringParam);
			case smaller_than:
				return new Filters.SmallerThan(filteringParam);
			case file:
				return new Filters.FileName(filteringParam);
			case prefix:
				return new Filters.Prefix(filteringParam);
			case suffix:
				return new Filters.Suffix(filteringParam);
			case writable:
				return new Filters.Writable(filteringParam);
			case executable:
				return new Filters.Executable(filteringParam);
			case hidden:
				return new Filters.Hidden(filteringParam);
			default:
				return null;
			}
		} catch (IllegalArgumentException e) {
			throw new FilterNameException();
		} catch (ParseException e) {
			throw new IllegalDateException(e.getMessage(), e.getErrorOffset());
		}
	}
	
	
	/**this method inserts the successfully filtered files into a TreeSet.  
	 * @param filters - the filters that need to be made.
	 * @param sourceDir The given sourceDir.
	 * @param tree - a TreeSet containing all filtered files 
	 * @throws YesNoException if the given String in neither YES nor NO.
	 * @throws FilterNameException if a given filter name is illegal. 
	 * @throws IllegalDateException if date is illegal.
	 */
	public static void doFilters(ArrayList<String[]> filters, File sourceDir, TreeSet<File> tree)
											throws  YesNoException, FilterNameException, IllegalDateException{
		try{
			//the recursion's base case.
			if (sourceDir.isFile()){
				if (FiltersWork.pass(filters,sourceDir)){
					tree.add(sourceDir);
				}
				return;
			}
			//inserts all files and folders in the dir into temp File array.
			File[] tempFiles = sourceDir.listFiles();
			for(int i=0; i<tempFiles.length; i++)
				doFilters(filters, tempFiles[i], tree);
		}
		catch (ParseException e) {
			throw new IllegalDateException(e.getMessage(), e.getErrorOffset());
		}
		
	}
	
	
	/**This method checks if a given file passes given filters.
	 * @param filters - the filters that need to be made.
	 * @param file - The filtered file. 
	 * @return true - If the given file passed all filters, false otherwise.
	 * @throws YesNoException if the given String in neither YES nor NO.
	 * @throws FilterNameException if a given filter name is illegal. 
	 * @throws IllegalDateException if date is illegal.
	 */
	public static boolean pass(ArrayList<String[]> filters, File file) 
								throws YesNoException, FilterNameException, IllegalDateException {
		try{
			boolean check;
			//gets into the [i][j] cell on filters.
			for(int i=0; i<filters.size(); i++){
				check = false;
				for (int j=0; !check && j<filters.get(i).length; j++){
					String[] line= filters.get(i)[j].split(FUNCTION_SPLITER);
					//setting the correct filter.
					FileFilter fil = getFilter(line[0], line[1]);
					//checks if the filter ends with NOT.
					if (line.length>2){
						check = !((FileFilter) fil).accept(file);	
					}
					else 
						check = ((FileFilter) fil).accept(file);			
				}
				if (!check)
					return false;
			}
			return true;
		}
		catch (ParseException e) { //throws IllegalDateException from getFilter method.
			throw new IllegalDateException(e.getMessage(), e.getErrorOffset());
		}
	}
}
